package com.gome.ss.core.schedule;

import java.util.List;
import java.util.concurrent.TimeoutException;

import org.apache.log4j.Logger;

import com.gome.spiderkit.client.UnknowServerException;
import com.gome.spiderkit.client.WebKit;
import com.gome.spiderkit.client.WebPage;
import com.gome.ss.common.Utils;
import com.gome.ss.core.datapipe.DataPipeInterface;
import com.gome.ss.core.download.SpiderDataMap;
import com.gome.ss.core.download.SpiderRequest;
import com.gome.ss.core.download.SpiderRequestInterface;
import com.gome.ss.core.download.SpiderResponse;
import com.gome.ss.core.plugin.Plugin;
import com.gome.ss.core.plugin.PluginManager;
import com.google.protobuf.InvalidProtocolBufferException;


public class RequestThreadTask implements ThreadTaskBase {
	
	protected static Logger logger = Logger.getLogger(RequestThreadTask.class);
	private ScheduleCore scheduleCore = null;
	boolean useSpecialQueue = false;
	
	public RequestThreadTask(ScheduleCore sc) {
		scheduleCore = sc;
	}
	
	public RequestThreadTask(ScheduleCore sc, boolean useSpecialQueue) {
		scheduleCore = sc;
		this.useSpecialQueue = useSpecialQueue;
	}
	
	@Override
	public void execute() {
		// TODO Auto-generated method stub
		
		while (true) {
			SpiderRequest request;
			if (useSpecialQueue)
				request = (SpiderRequest) scheduleCore.pollRequestFromSpecialQueue();
			else
				request = (SpiderRequest) scheduleCore.pollRequestFromQueue();

			if (request == null) {
				while (true) {
					try {
						Thread.sleep(200);
						if (useSpecialQueue)
							request = (SpiderRequest) scheduleCore.pollRequestFromSpecialQueue();
						else
							request = (SpiderRequest) scheduleCore.pollRequestFromQueue();
						if (request != null)
							break;
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						logger.error(Utils.getTrace(e));
					}
				}
			} else if (!request.canRetry())
				continue;
			
			request.accumulationTryTimes();
			scheduleCore.addTaskReferenceInThreadPool(request.getSourceTaskID());
			
			WebKit webkit = null;
			WebPage page = null;
			boolean hasCurrentPageRequest = false;
			Thread thread = Thread.currentThread();
			String currentPagetitle = "";
			
			try {
				if (useSpecialQueue)
					logger.info("[Thread " + thread.getId() + "] From Special Queue : " + request.getUrl().getLink());
				
				logger.info("[Thread " + thread.getId() + "] Request " + request.getPluginName() + "." + request.getPluginQualified() + " " + " link -- " + request.getUrl().getLink() + " triedCount : " + request.triedCount());
				
				if( !PluginManager.getInstance().getPlugin(request.getPluginName(), request.getPluginQualified()).getHandle().beforDownLoad(request) ) {
					logger.info("[Thread " + thread.getId() + "] Abandon " + request.getPluginName() + "." + request.getPluginQualified() + " " + " link -- " + request.getUrl().getLink());
					continue;
				}
				
				if (!useSpecialQueue) {
					if (scheduleCore.taskNeedStop(request.getSourceTaskID())) {
						logger.info("[Thread " + thread.getId() + "] Task Stop " + request.getPluginName() + "." + request.getPluginQualified() + " " + " link -- " + request.getUrl().getLink());
						continue;
					}
					
					webkit = new WebKit(request.getGroupName(), request.getIsStatic());

					if (request.cookies() != null)
						page = webkit.get(request.getUrl().getLink(), request.cookies(), 120000, 150000);
					else
						page = webkit.get(request.getUrl().getLink(), 120000, 150000);
				} else {
					page = request.getReadyPage();
					page.threadConstruct();
					webkit = page.getWebKit();
				}

				if (page.errorCode() < 0) {
					if (request.canRetry()) {
						logger.info("[Thread " + thread.getId() + "] Get Error [" + page.errorCode() + "] Retry " + request.getPluginName() + "." + request.getPluginQualified() + " " + " link -- " + request.getUrl().getLink() + " triedCount : " + request.triedCount());
						scheduleCore.pushRequestToQueue(request, request.getPriority());
					}
					continue;
				}
				
				SpiderResponse resp = new SpiderResponse(page, request.getPluginName(), request.getPluginQualified(), 
						request.getPriority(), request.triedCount(), request.retryCount());
				resp.identity = request.getIID();
				resp.setCData(request.getData());
				resp.setCurrentPage(request.currentPage());
				
				Plugin plugin = PluginManager.getInstance().getPlugin(request.getPluginName(), request.getPluginQualified());
				
				plugin.getHandle().onDownLoadFinished(resp);
				if (resp.needRetry()) {
					if (request.canRetry() || page.isFailed()) {
						logger.info("[Thread " + thread.getId() + "] Retry after onDownLoadFinished " + request.getPluginName() + "." + request.getPluginQualified() + " " + " link -- " + request.getUrl().getLink() + " triedCount : " + request.triedCount());
						scheduleCore.pushRequestToQueue(request, request.getPriority());
					}
					continue;
				}
				
				currentPagetitle = page.getTitle();
				
				SpiderDataMap data = plugin.getHandle().parseData(resp);
				if (resp.needRetry() || page.isFailed()) {
					if (request.canRetry()) {
						logger.info("[Thread " + thread.getId() + "] Retry after parseData " + request.getPluginName() + "." + request.getPluginQualified() + " " + " link -- " + request.getUrl().getLink() + " triedCount : " + request.triedCount());
						scheduleCore.pushRequestToQueue(request, request.getPriority());
					}
					continue;
				}
				
				List<SpiderRequestInterface> reqs = plugin.getHandle().parseLink(resp);
				if (resp.needRetry()) {
					if (request.canRetry() || page.isFailed()) {
						logger.info("[Thread " + thread.getId() + "] Retry after parseLink " + request.getPluginName() + "." + request.getPluginQualified() + " " + " link -- " + request.getUrl().getLink() + " triedCount : " + request.triedCount());
						scheduleCore.pushRequestToQueue(request, request.getPriority());
					}
					continue;
				}
				
				if (reqs != null) {
					for (SpiderRequestInterface req : reqs) {
						
						req.setSourceTaskID(request.getSourceTaskID());
						if (req.isPageReady()) {
							SpiderRequest r = (SpiderRequest) req;
							if (!req.isNewPageReady())
								hasCurrentPageRequest = true;
						}

						scheduleCore.pushRequestToQueue(req, req.getPriority());
					}
				}
				if (data != null) {
					data.setQualified(plugin.getHandle().getPluginQualified());
					
					DataPipeInterface dataPipe = plugin.getHandle().datePipe();
					if (dataPipe != null)
						dataPipe.saveData(data);
				}
			} catch (Exception e) {
				logger.error("[Thread " + thread.getId() +"] " + Utils.getTrace(e));
				
				if (request.isPageReady()) {
					request.setIsPageReady(false);
					request.setIsNewPageReady(false);
				}
				
				// retry here
				if (request.canRetry()) {
					scheduleCore.pushRequestToQueue(request, request.getPriority());
				}
			} finally {
				scheduleCore.removeTaskInThreadPool(request.getSourceTaskID());
				
				if (!hasCurrentPageRequest) {
					if (page != null) {
						try {
							page.destory();
						} catch (Exception e) {
							// TODO Auto-generated catch block
							logger.error("[Thread " + thread.getId() +"] " + Utils.getTrace(e));
						}
					}
					
					if (webkit != null) {
						webkit.release();
					}
				}
				
				logger.info("[Thread " + thread.getId() + "] Request end : " + request.getPluginName() + "." + request.getPluginQualified() + " " + " link -- " + request.getUrl().getLink() + " title -- " + currentPagetitle + " triedCount : " + request.triedCount());
			}
		}
	}

}
